/* tslint:disable */
export function polyfill(): void {
  const version = detectIE();
  if (Number(version) <= 10) {
    return;
  }

  function addRemoveToArray(arr): void {
    arr.forEach((item): void => {
      if (Object.prototype.hasOwnProperty.call(item, 'remove')) {
        return;
      }
      Object.defineProperty(item, 'remove', {
        configurable: true,
        enumerable: true,
        writable: true,
        value: function remove(): void {
          this.parentNode.removeChild(this);
        },
      });
    });
  }
  // IE下无element.remove(),故新增
  addRemoveToArray([Element.prototype, CharacterData.prototype, DocumentType.prototype]);

  // eslint-disable-next-line
  // IE下无matches方法，故新增
  if (!Element.prototype.matches) {
    Element.prototype.matches = Element.prototype.webkitMatchesSelector;
  }

  function closest(s: any): Element {
    let el = this;

    do {
      if (el.matches(s)) {
        return el;
      }
      el = el.parentElement || el.parentNode;
    } while (el !== null && el.nodeType === 1);
    return null;
  }

  // IE下无closest方法，故新增
  // eslint-disable-next-line
  if (!Element.prototype.closest) {
    Element.prototype.closest = closest;
  }

  // IE下无includes方法
  supportIncludes();

  // IE SVG支持classList
  supportClassList();
}

/**
 * detect IE
 * returns version of IE or false, if browser is not Internet Explorer
 // Test values; Uncomment to check result …

 // IE 10
 // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';

 // IE 11
 // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';

 // Edge 12 (Spartan)
 // ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0';

 // Edge 13
 // ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
 */
export function detectIE(): number | boolean {
  const ua = window.navigator.userAgent;

  const msie = ua.indexOf('MSIE ');
  if (msie > 0) {
    // IE 10 or older => return version number
    return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
  }

  const trident = ua.indexOf('Trident/');
  if (trident > 0) {
    // IE 11 => return version number
    const rv = ua.indexOf('rv:');
    return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
  }

  const edge = ua.indexOf('Edge/');
  if (edge > 0) {
    // Edge (IE 12+) => return version number
    return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
  }

  // other browser
  return false;
}

export function supportClassList(): any {
  const proto = Element.prototype;
  if ('classList' in proto) {
    return;
  }

  Object.defineProperty(proto, 'classList', {
    get() {
      const _this: SVGElement = this;

      function contains(name: string): any {
        return _this.className.baseVal.split(' ').includes(name);
      }

      function add(name: string): void {
        if (!this.contains(name)) {
          const names = _this.className.baseVal.split(' ').filter((a): boolean => !!a);
          names.push(name);
          _this.setAttribute('class', names.join(' '));
        }
      }

      function remove(name: string): void {
        if (this.contains(name)) {
          const names = _this.className.baseVal.split(' ').filter((a): boolean => !!a && a !== name);
          _this.setAttribute('class', names.join(' '));
        }
      }

      function toggle(name: string): void {
        this.contains(name) ? this.remove(name) : this.add(name);
      }

      return {
        contains,
        add,
        remove,
        toggle,
      };
    },
  });
}

export function supportIncludes(): boolean {
  function includes(search: string, startIdx: any): boolean {
    let start = startIdx;
    if (typeof start !== 'number') {
      start = 0;
    }

    if (start + search.length > this.length) {
      return false;
    } else {
      return this.indexOf(search, start) !== -1;
    }
  }

  if (!String.prototype.includes) {
    // eslint-disable-next-line no-extend-native
    String.prototype.includes = includes;
  }

  function value(valueToFind, fromIndex): boolean {
    if (this === null || this === undefined) {
      throw new TypeError('"this" is null or not defined');
    }

    // 1. Let O be ? ToObject(this value).
    const o = Object(this);

    // 2. Let len be ? ToLength(? Get(O, "length")).
    const len = o.length >>> 0;

    // 3. If len is 0, return false.
    if (len === 0) {
      return false;
    }

    // 4. Let n be ? ToInteger(fromIndex).
    //    (If fromIndex is undefined, this step produces the value 0.)
    const n = fromIndex | 0;

    // 5. If n ≥ 0, then
    //  a. Let k be n.
    // 6. Else n < 0,
    //  a. Let k be len + n.
    //  b. If k < 0, let k be 0.
    let k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

    function sameValueZero(x, y): boolean {
      return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
    }

    // 7. Repeat, while k < len
    while (k < len) {
      // a. Let elementK be the result of ? Get(O, ! ToString(k)).
      // b. If SameValueZero(valueToFind, elementK) is true, return true.
      if (sameValueZero(o[k], valueToFind)) {
        return true;
      }
      // c. Increase k by 1.
      k++;
    }

    // 8. Return false
    return false;
  }

  if (!Array.prototype.includes) {
    const config = {
      value,
      enumerable: true,
      writable: true,
      configurable: true,
    };
    // eslint-disable-next-line no-extend-native
    Object.defineProperty(Array.prototype, 'includes', config);
  }
  return undefined;
}
